Research
Security News
Quasar RAT Disguised as an npm Package for Detecting Vulnerabilities in Ethereum Smart Contracts
Socket researchers uncover a malicious npm package posing as a tool for detecting vulnerabilities in Etherium smart contracts.
react-focus-lock
Advanced tools
The react-focus-lock package is a React component designed to trap focus within a DOM element. It is commonly used to ensure that keyboard users can navigate modal dialogs and other pop-up UI elements without accidentally interacting with the rest of the page.
Focus Trapping
This feature traps the focus within the modal dialog. When the modal is open, the focus cycles through the interactive elements inside the modal and does not move to the background elements.
{"import React from 'react';\nimport FocusLock from 'react-focus-lock';\n\nconst Modal = ({ onClose }) => (\n <FocusLock>\n <div className='modal'>\n <button onClick={onClose}>Close</button>\n {/* other modal contents */}\n </div>\n </FocusLock>\n);"}
AutoFocus and Return Focus
This feature automatically focuses the first focusable element within the FocusLock on mount and returns the focus to the initially focused element when the FocusLock is unmounted.
{"import React from 'react';\nimport FocusLock from 'react-focus-lock';\n\nconst Modal = ({ onClose }) => (\n <FocusLock autoFocus={true} returnFocus={true}>\n <div className='modal'>\n <button onClick={onClose}>Close</button>\n {/* other modal contents */}\n </div>\n </FocusLock>\n);"}
Focus Grouping
This feature allows grouping of focusable elements. Focus can be moved inside a group, and it will be contained within the elements of that group.
{"import React from 'react';\nimport FocusLock, { MoveFocusInside } from 'react-focus-lock';\n\nconst Group = () => (\n <div>\n <MoveFocusInside>\n <button>Button1</button>\n </MoveFocusInside>\n <MoveFocusInside>\n <button>Button2</button>\n </MoveFocusInside>\n </div>\n);\n\nconst App = () => (\n <FocusLock group='group1'>\n <Group />\n </FocusLock>\n);"}
react-modal is a package that provides accessible modals for React applications. It includes the ability to trap focus within the modal, similar to react-focus-lock, but it is specifically designed for modal dialog creation and management.
react-aria-modal is a fully accessible React modal component that manages focus. It also traps focus within the modal, similar to react-focus-lock, and provides a comprehensive solution for creating accessible modals with ARIA attributes.
react-trap-focus is a package that provides focus trapping functionality. It is similar to react-focus-lock in that it traps focus within a specified element, but it may have different implementation details or additional features.
It is a trap! We got your focus and will not let him out!
a11y
is asking for.Trusted by Atlassian AtlasKit, ReachUI, SmoothUI, Storybook and we will do our best to earn your trust too!
💡 focus locks is only the first part, there are also scroll lock and text-to-speech lock you have to use to really "lock" the user. Try react-focus-on to archive everything above, assembled in the right order.
Just wrap something with focus lock, and focus will be moved inside
on mount.
import FocusLock from 'react-focus-lock';
const JailForAFocus = ({onClose}) => (
<FocusLock>
You can not leave this form
<button onClick={onClose} />
</FocusLock>
);
Demo - https://codesandbox.io/s/5wmrwlvxv4.
From MDN Article about accessible dialogs:
This one is about managing the focus.
I've got a good article about focus management, dialogs and WAI-ARIA.
FocusLock would work perfectly even with no props set.
FocusLock has few props to tune behavior, all props are optional:
[disabled
, to disable(enable) behavior without altering the tree.returnFocus
, to return focus into initial position on unmount(not disable).By default
returnFocus
is disabled, so FocusLock will not restore original focus on deactivation.
This is expected behavior for Modals, but it is better to implement it by your self.
persistentFocus=false
, requires any element to be focused. This also disables text selections inside, and outside focus lock.autoFocus=true
, enables or disables focusing into on Lock activation. If disabled Lock will blur an active focus.noFocusGuards=false
disabled focus guards - virtual inputs which secure tab index.group='''
named focus group for focus scattering aka combined lock targetsshards=[]
an array of ref
pointing to the nodes, which focus lock should consider and a part of it. This is another way focus scattering.whiteList=fn
you could whitelist locations FocusLock should carry about. Everything outside it will ignore. For example - any modals.as='div'
if you need to change internal div
element, to any other. Use ref forwarding to give FocusLock the node to work with.lockProps={}
to pass any extra props (except className) to the internal wrapper.By default tabbing
in OSX sees
only controls, but not links or anything else tabbable
. This is system settings, and Safari/FireFox obey.
Press Option+Tab in Safary to loop across all tabbables, or change the Safary settings. There is no way to fix FireFox, unless change system settings (Control+F7). See this issue for more information.
As long you cannot use autoFocus
prop -
cos "focusing" should be delayed to Trap activation, and autoFocus will effect immediately -
Focus Lock provide a special API for it
data-autofocus
on the element.data-autofocus-inside
on the element to focus on something inside.AutoFocusInside
component, as named export of this library. import FocusLock, { AutoFocusInside } from 'react-focus-lock';
<FocusLock>
<button>Click</button>
<AutoFocusInside>
<button>will be focused</button>
</AutoFocusInside>
</FocusLock>
// is the same as
<FocusLock>
<button>Click</button>
<button data-autofocus>will be focused</button>
</FocusLock>
If there is more than one auto-focusable target - the first will be selected. If it is a part of radio group, and rest of radio group element are also autofocusable(just put them into AutoFocusInside) - checked one fill be selected.
AutoFocusInside
will work only on Lock activation, and does nothing, then used outside of the lock.
You can use MoveFocusInside
to move focus inside with or without lock.
import { MoveFocusInside } from 'react-focus-lock';
<MoveFocusInside>
<button>will be focused</button>
</MoveFocusInside>
Use focus scattering to handle portals
groups
. Just create a few locks (only one could be active) with a same group nameconst PortaledElement = () => (
<FocusLock group="group42" disabled={true}>
// "discoverable" portaled content
</FocusLock>
);
<FocusLock group="group42">
// main content
</FocusLock>
shards
. Just pass all the pieces to the "shards" prop.const PortaledElement = () => (
<div ref={ref}>
// "discoverable" portaled content
</div>
);
<FocusLock shards={[ref]}>
// main content
</FocusLock>
const PortaledElement = () => (
<div>
// NON-"discoverable" portaled content
</div>
);
<FocusLock shards={[ref]}>
// main content
<PortaledElement />
</FocusLock>
Components
You may use as
prop to change what Focus-Lock will render around children
.
<FocusLock as="section">
<button>Click</button>
<button data-autofocus>will be focused</button>
</FocusLock>
<FocusLock as={AnotherComponent} lockProps={{anyAnotherComponentProp: 4}}>
<button>Click</button>
<span>Hello there!</span>
</FocusLock>
As you may know - FocusLock is adding Focus Guards
before and after lock to remove some side effects, like page scrolling.
But shards
will not have such guards, and it might be not so cool to use them - for example if no tabbable
would be
defined after shard - you will tab to the browser chrome.
You may wrap shard with InFocusGuard
or just drop InFocusGuard
here and there - that would solve the problem.
import {InFocusGuard} from 'react-focus-lock';
// wrap with
<InFocusGuard>
<button />
</InFocusGuard>
// place before and after
<InFocusGuard />
<button />
<InFocusGuard />
InFocusGuards would be active(tabbable) only when tabble, it protecting, is focused.
If only your modal is the last tabble element on the body - you might remove the Tailing Guard, to allow user tab into address bar.
<InFocusGuard/>
<button />
// there is no "tailing" guard :)
returnFocus
enabled, and it's gonna to be unmounted - focus will be returned after zero-timeout.returnFocus
did not set, and you are going to control focus change by your own - keep in mindReact will first call Parent.componentWillUnmount, and next Child.componentWillUnmount
Thus means - Trap will be still active, be the time you may want move(return) focus on componentWillUnmount. Please deffer this action with a zero-timeout.
Everything thing is simple - react-focus-lock just don't let focus leave boundaries of a component, and is doing something only if escape attempt was successful.
It is not altering tabbing behavior at all. We are good citizens.
Uses focus-lock under the hood. It does also provide support for Vue.js and Vanilla DOM solutions
Two different focus-lock-managers or even different version of a single one, active simultaneously will FIGHT!
Focus-lock will surrender, as long any other focus management library will not.
You may wrap some render branch with FreeFocusInside
, and react-focus-lock will ignore
any focus inside marked node, thus landing a peace.
import { FreeFocusInside } from 'react-focus-lock';
<FreeFocusInside>
<div id="portal-for-modals">
in this div i am going to portal my modals, dont fight with them please
</div>
</FreeFocusInside>
Even the better is to whiteList
FocusLock areas - for example "you should handle only React Stuff in React Root"
<FocusLock whiteList={node => document.getElementById('root').contains(node)}>
...
</FocusLock>
PS: please use webpack or yarn resolution for force one version of react-focus-lock used
webpack.conf
resolve: {
alias: {
'react-focus-lock': path.resolve(path.join(__dirname, './node_modules/react-focus-lock'))
...
To create a "right" modal dialog you have to:
You may use react-focus-on to archive everything above, assembled in the right order.
About 3kb, minified and gzipped.
MIT
FAQs
It is a trap! (for a focus)
We found that react-focus-lock demonstrated a healthy version release cadence and project activity because the last version was released less than a year ago. It has 0 open source maintainers collaborating on the project.
Did you know?
Socket for GitHub automatically highlights issues in each pull request and monitors the health of all your open source dependencies. Discover the contents of your packages and block harmful activity before you install or update your dependencies.
Research
Security News
Socket researchers uncover a malicious npm package posing as a tool for detecting vulnerabilities in Etherium smart contracts.
Security News
Research
A supply chain attack on Rspack's npm packages injected cryptomining malware, potentially impacting thousands of developers.
Research
Security News
Socket researchers discovered a malware campaign on npm delivering the Skuld infostealer via typosquatted packages, exposing sensitive data.